/**
 * Copyright (c) suzuki ryoutoku
 * See this code regarding the Apache License Version 2.0
 * @file main.cpp
 * @author suzuki ryoutoku
 */

//=============================================================================
//	Preporcessor
//=============================================================================

#include <gtk/gtk.h>
#include <iostream>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <gdk/gdkkeysyms.h>
#include <unistd.h>
#include <sys/time.h>
#include <pthread.h>
using namespace std;

#include "include/library.h"
using namespace library::graphics;
using namespace library::log;

//=============================================================================
//	Alias 
//=============================================================================
#define APPLICATION_NAME "StripExperiment"
#define MAIN_WINDOW_WIDTH 550
#define MAIN_WINDOW_HEIGHT 400
#define NOTEBOOK_WIDTH 150
#define NOTEBOOK_HEIGHT 350
#define HIERARCHY_VIEW_TAB_LABEL "hierarchy"
#define ATTRIBUTE_VIEW_TAB_LABEL "attribute"
#define DRAW_AREA_WIDTH 300
#define DRAW_AREA_HEIGHT 300
#define LOG_FILENAME "stripexperiment.log"

#define OPEN_PCMFILE_MENU "Open pcm file"
#define OPNE_OBJFILE_MENU "Open obj file"
#define OPEN_3DSFILE_MENU "Open 3ds file"

//=============================================================================
//	Define class
//=============================================================================
/**
 * Global parameter manager.
 * \note
 * All global parameter is controled by this class.
 * This class instance is unique in application.
 * Mechanism of this class refer to singleton pattern.
 *
 * All members are allowed you to get and set by inline method.
 *
 * @author suzuki ryoutoku
 * @date 2007-12-17
 * @version 1.0
 */
class GlobalParameter
{
  // closed member
private:
  GtkWidget* 	 m_main_window;//!< Main window of this application
  GtkWidget* m_parent_drawarea;/**< 
								  Drawing window's parent for 3d model by 
								  opengl.
								  User can not see this window.
								  User can see this windows's child window.
							   */
  GtkTreeView* m_hierarchyview;/**< 
								  This member is Gtk's tree view window.
								  Place of this window is left in Main window.
								*/
  GtkTreeView* m_attributeview;
  GtkWidget*	 m_symboltable;//!< This window is to show symbol table.
  RenderingManager*		  m_rm;//!< This application's rendering manager.
  Model* 			   m_model;/**<
								  This application has only pointer of 
								  model data 
							   */
  DrawPolygons*	   m_selection;//!< selection polygon
  DrawString m_shapeinfomation;//!< To display face & vertex sum infomation
  DrawString 			 m_fps;//!< To display fps infomation 
  Sprite*		  m_background;//!< To draw background image
  ImageData*	       m_image;//!< Background image
  gdouble			m_before_x;//!< Temporary data to be stored Mouse's x
  gdouble 			m_before_y;//!< Temporary data to be stored Mouse's y
  gdouble			m_before_z;//!< Temporary data to be stored Mouse's scrol
  GtkWidget*	   m_line_menu;//!< line menu widget
  char	m_data_directory[1024];//!< This Application's current directory
  char	m_home_directory[1024];//!< This Application's home directory
  double				 m_div;//!< 
  unsigned int		m_keystate;//!< now user input key.
  GtkProgressBar* 	m_progress;
  GtkWidget* m_progress_dialog;
  unsigned int m_strip_counter;

  // opened method
public:
  GlobalParameter();
  ~GlobalParameter();

  void resetMouseCoordinate(void);
  void substituteMouseCoordinate(gdouble ix = -1,
								 gdouble iy = -1,
								 gdouble iz = -1);
  void releaseModelData(void);

  bool readTextureFile(Read3ds* reader);

  bool initializeaLogManager(void);
  bool createRenderingManager(LogManager* log);
  bool createBackground(void);
  bool createDefaultData(void);
  bool createDrawingString(void);

  bool createHierarchyViewWindow(void);
  bool createAttributeViewWindow(void);
  bool createNotebook(GtkWidget* hbox);
  bool createParentDrawArea(GtkWidget* hbox);
  

  // inline setter & getter
public:
  GtkWidget* getM_main_window(){return this->m_main_window;}
  void setM_main_window(GtkWidget* arg){this->m_main_window = arg;}

  GtkWidget* getM_parent_drawarea(void){return this->m_parent_drawarea;}
  void setM_parent_drawarea(GtkWidget* arg){m_parent_drawarea = arg;}

  GtkTreeView* getM_hierarchyview(){return m_hierarchyview;}
  void setM_hierarchyview(GtkTreeView* arg){this->m_hierarchyview = arg;}

  GtkTreeView* getM_attributeview(){return m_attributeview;}
  void setM_attributeview(GtkTreeView* arg){this->m_attributeview = arg;}


  RenderingManager* getM_rm(){return m_rm;}
  void setM_rm(RenderingManager* arg){this->m_rm = arg;}

  Model* getM_model(void){return m_model;}
  void setM_model(Model* arg){m_model = arg;}

  DrawPolygons* getM_selection(void){return (this->m_selection);}
  void setM_selection(DrawPolygons* arg){m_selection=arg;}

  gdouble getM_before_x(void){return this->m_before_x;}
  gdouble getM_before_y(void){return this->m_before_y;}
  gdouble getM_before_z(void){return this->m_before_z;}

  void setM_before_x(gdouble arg){this->m_before_x=arg;}
  void setM_before_y(gdouble arg){this->m_before_y=arg;}
  void setM_before_z(gdouble arg){this->m_before_z=arg;}

  DrawString* getM_shapeinfomation(void){return &(this->m_shapeinfomation);}
  DrawString* getM_fps(void){return &(this->m_fps);}

  GtkWidget* getM_line_menu(void){return this->m_line_menu;}
  void setM_line_menu(GtkWidget* arg){this->m_line_menu=arg;}

  char* getM_data_directory(){return this->m_data_directory;}
  char* getM_home_directory(){return this->m_home_directory;}
  double getM_div(void){return this->m_div;}
  void setM_div(double arg){this->m_div=arg;}

  unsigned int getM_keystate(void){return this->m_keystate;}
  void setM_keystate(unsigned int arg){this->m_keystate=arg;}

  GtkProgressBar* getM_progress(void){return this->m_progress;}
  void setM_progress(GtkProgressBar* arg){this->m_progress=arg;}

  GtkWidget* getM_progress_dialog(void){return this->m_progress_dialog;}
  void setM_progress_dialog(GtkWidget* arg){this->m_progress_dialog=arg;}
  
  unsigned int getM_strip_counter(void){return this->m_strip_counter;}
  void setM_strip_counter(unsigned int arg){this->m_strip_counter=arg;}

  Sprite* getM_background(void){return this->m_background;}
  void setM_background(Sprite* arg){this->m_background=arg;}

  ImageData* getM_image(void){return this->m_image;}
  void setM_image(ImageData* arg){this->m_image=arg;}

  

  // closed class member
private:
  static GlobalParameter instance;


  // opened class method
public:
  static GlobalParameter* getInstance();
};

//=============================================================================
//	Declare function
//=============================================================================
// callback of menu items
void cb_menuitem_response(gchar* string);

// callback of menu line
void cb_menu_line_toggled(GtkCheckMenuItem *checkmenuitem);

// callback of scaling dialog
void cb_scaling(GtkScale* scale, gpointer data);

// callback of activate tree view
gboolean cb_tree_item_double_clicked(GtkTreeView *treeview,
									 GtkTreePath *path,
									 GtkTreeViewColumn* column,
									 gpointer data);

// callback of tree view
void cb_status_toggled(GtkCellRendererToggle *renderer ,
					   gchar *path_string ,
					   gpointer user_data);

// callback of draw event
gint cb_expose(GtkWidget* widget, GdkEventExpose* event, gpointer data);

// callback of main window resize event
void cb_size_allocate(GtkWidget *,
					  gpointer,
					  gpointer);

// callback of mouse event
gboolean cb_button_press_event(GtkWidget* widget, 
							   GdkEventButton* event, 
							   gpointer data);
// callback of mouse event
gboolean cb_motion_notify_event(GtkWidget         *widget,
                                GdkEventMotion      *event);

// callback of keybord event
gboolean cb_key_press_event(GtkWidget *widget,
							GdkEventKey *event);
// callback of keybord event
gboolean cb_key_release_event(GtkWidget *widget,
							  GdkEventKey *event);

// callback of mouse scroll
gboolean cb_scroll_event(GtkWidget *widget,
						 GdkEventScroll *event);


// test function...
void select_list(GtkTreeView *treeview);

// callback in set forcus event
gboolean cb_focus_in_event(GtkWidget *,
						   GdkEvent *,
						   gpointer);

GtkTreeView* InitializeAttributeView(GtkTreeView* treeview, 
									 GtkTreeStore* store, 
									 bool flag);


// This function is equiped in thread.
void* thread_function(void* args);

// This function is to create bitmapdata from jpg file
bool CreateBitmapFromJpgfile(BITMAPINFO*,unsigned int** , const char* );

void TestFunction(library::graphics::Screen* screen);

// This function creates main window.
GtkWidget* CreateMainWindow(void);

// This function creates menu bar.
GtkWidget* CreateMenuBar(void);

//=============================================================================
//	GlobalParameter's memthod
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @date 2007-12-19
 * @version 1.0
 */
GlobalParameter::GlobalParameter()
{
  this->m_main_window = NULL;
  this->m_parent_drawarea = NULL;
  this->m_hierarchyview = NULL;
  this->m_attributeview = NULL;
  this->m_symboltable = NULL;
  this->m_rm = NULL;
  this->m_model = NULL;
  this->m_line_menu = NULL;
  this->m_background=NULL;
  this->m_image=NULL;
  this->resetMouseCoordinate();
  this->m_div = 0.01;
  strcpy(this->m_data_directory, getenv("HOME"));// To get current dir => PWD
  sprintf(this->m_home_directory, "%s/.%s",getenv("HOME"), APPLICATION_NAME);
  this->m_keystate=0;
  m_progress=NULL;
  m_progress_dialog=NULL;
  m_strip_counter=0;
}

/**
 * @author suzuki ryoutoku
 * @date 2007-12-19
 * @version 1.0
 */
GlobalParameter::~GlobalParameter()
{
  this->releaseModelData();
  delete m_rm;
  if( m_background != NULL ) delete m_background;
  if( m_image != NULL) delete m_image;
}

/**
 * @author suzuki ryoutoku
 * @date 2007-12-20
 * @version 1.0
 */
void GlobalParameter::releaseModelData(void)
{
  m_rm->getM_screen(0)->cancelGraphicalCommand(m_model);
  delete this->m_model;
  this->m_model = NULL;

  m_rm->getM_screen(0)->cancelGraphicalCommand(m_selection);

  if( m_selection != NULL ){
	delete m_selection;
	this->m_selection = NULL;
  }
}


/**
 * @author suzuki ryoutoku
 * @date 2007-12-19
 * @version 1.0
 */
void GlobalParameter::resetMouseCoordinate(void)
{
  this->m_before_x=0;
  this->m_before_y=0;
  this->m_before_z=0;
}

/**
 * @param ix -1 in defalut
 * @param iy -1 in defalut
 * @param iz -1 in defalut
 * @author suzuki ryoutoku
 * @date 2007-12-20
 * @version 1.0
 */
void GlobalParameter::substituteMouseCoordinate(gdouble ix,
												gdouble iy,
												gdouble iz)
{
  if( ix != -1 ) this->m_before_x = ix;
  if( iy != -1 ) this->m_before_y = iy;
  if( iz != -1 ) this->m_before_z = iz;
}

/**
 * This method is roler reading texture file used in 3ds file.
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-28
 */
bool GlobalParameter::readTextureFile(Read3ds* read3ds)
{
  vector<library::max::Material*>* materials = read3ds->getM_material();
  if( materials->size() == 0 ) return true;
  vector<string> texfilename;
  
  vector<library::max::Material*>::iterator ite = materials->begin();
  while( ite != materials->end() ){
	if( (*ite)->getM_texture_filename() != NULL &&
		(*ite)->getM_texture_filename()[0] != '\0'
		){
	  texfilename.push_back(string((*ite)->getM_texture_filename()));
	}
	ite++;
  }

  // change directory to being 3ds file 
  chdir(this->getM_data_directory());

  // Next codes are to load texture file & create image data
  for( unsigned int i = 0; i < texfilename.size(); i++){
	if( string::npos != texfilename[i].rfind("bmp") ||
		string::npos != texfilename[i].rfind("BMP") ){
	  string tmp = texfilename[i];
	  ImageDataManager::getInstance()->createImageData(tmp);
	}else if( string::npos != texfilename[i].rfind("jpg") ||
			  string::npos != texfilename[i].rfind("JPG") ){
	  BITMAPINFO info;
	  unsigned int* bitpattern;

	  if( true == CreateBitmapFromJpgfile(&info, 
										  &bitpattern, 
										  texfilename[i].c_str()) ){
		ImageData* image = new ImageData(texfilename[i].c_str(),
										 &info,
										 bitpattern);
		ImageDataManager::getInstance()->assignTexId(image);
		delete [] bitpattern;
	  }
	}
  }
  return true;
}

/**
 * Initialize log manager
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-5-22
 */
bool GlobalParameter::initializeaLogManager(void)
{
  char tmp[1024];
  LogManager::getInstance()->initialize(string(LOG_FILENAME));
  LogManager::getInstance()->print("Log file of StripExperiment\n");
  return true;
}

/**
 * This method creates Rendering Manger about draw area window.
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-5-18
 */
bool GlobalParameter::createRenderingManager(LogManager* log)
{
  GdkWindow* window = m_parent_drawarea->window;
  this->m_rm = new RenderingManager(GDK_WINDOW_XDISPLAY(window), 
									GDK_WINDOW_XWINDOW(window),
									log);

  m_rm->resize(m_parent_drawarea->allocation.width,
			   m_parent_drawarea->allocation.height);
}

/**
 * This method creates default data for application.
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-5-14
 */
bool GlobalParameter::createDefaultData(void)
{
  BITMAPINFO info;
  unsigned int* bitpattern;
  char filename[256];
  sprintf(filename,
		  "%s/data.jpg", 
		  this->m_home_directory);
  
  if( true == CreateBitmapFromJpgfile(&info, &bitpattern, filename) ){
	this->setM_image( new ImageData("data",
									&info,
									bitpattern));
	delete [] bitpattern;
	ImageDataManager::getInstance()->assignTexId(this->getM_image());
  }else{
	cout << "Can not find data.jpg file" << endl;
  }
  
  this->setM_model(new Model(true));
  this->setM_selection(new DrawPolygons(true, 
										m_model->getM_vertex(),
										m_model->getM_normal(),
										m_model));
  this->m_rm->getM_screen(0)->registGraphicalCommand(m_model);
  this->m_rm->getM_screen(0)->registGraphicalCommand(m_selection);
  m_model->setTextureID(ImageDataManager::getInstance());
  return true;
}

/**
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-5-18
 */
bool GlobalParameter::createBackground(void)
{
  this->setM_background(new Sprite());
  this->getM_background()->setM_rect(0,0,100,100);
  this->getM_background()->setM_color( Color<float>(1.0f,1.0f,1.0f,1.0f) );
  this->m_rm->getM_screen(0)->registGraphicalCommand(this->getM_background());
  return true;
}

/**
 *
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-5-18
 */
bool GlobalParameter::createDrawingString(void)
{
  char tmp[256];
  sprintf(tmp,
		  "face sum = %d node sum = %d", 
		  m_model->getFaceSum(),
		  m_model->getM_vertex_sum());
  m_shapeinfomation.setM_message(tmp);
  m_rm->getM_screen(0)->registGraphicalCommand(&m_shapeinfomation);
  sprintf(tmp,"fps = 0");
  m_fps.setM_message(tmp);
  m_fps.setM_line_number(1);
  m_rm->getM_screen(0)->registGraphicalCommand(&m_fps);
  return true;
}

/**
 * Create tree view for setting graphic 
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-5-19
 */
bool GlobalParameter::createAttributeViewWindow(void)
{
  GtkTreeStore* store = gtk_tree_store_new(1, G_TYPE_STRING);
  GtkTreeView* treeview = (GtkTreeView*)gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
  GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
  GtkTreeViewColumn* column = column = gtk_tree_view_column_new();

  gtk_tree_view_column_pack_start(column, renderer, FALSE);
  gtk_tree_view_column_set_attributes(column,
									  renderer,
									  "text",
									  0,
									  NULL);
  g_signal_connect(treeview,"row-activated",
				   G_CALLBACK(cb_tree_item_double_clicked),
				   (gpointer)NULL);
  gtk_tree_view_append_column(GTK_TREE_VIEW(treeview),column);
  gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
  InitializeAttributeView(treeview, store, false);
  this->m_attributeview = treeview;
  
  return true;
}

/**
 * This method creates tree view window
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-5-19
 */
bool GlobalParameter::createHierarchyViewWindow(void)
{
  GtkTreeStore* treestore = gtk_tree_store_new(2,
											   G_TYPE_BOOLEAN,
											   G_TYPE_STRING);
  m_hierarchyview = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(treestore)));

  GtkCellRenderer* renderer;
  GtkTreeViewColumn* column;

  // toggle
  renderer = gtk_cell_renderer_toggle_new ();
  column = gtk_tree_view_column_new();
  gtk_tree_view_column_set_title(column , "show");
  gtk_tree_view_column_pack_start(column , renderer , FALSE);
  gtk_tree_view_column_set_attributes(column , 
									  renderer ,
									  "active" , 
									  0,
									  NULL);
  gtk_tree_view_append_column(GTK_TREE_VIEW(m_hierarchyview),
							  column);

  g_signal_connect(renderer , 
				   "toggled" ,
				   G_CALLBACK(cb_status_toggled),
				   m_hierarchyview);
  
  // text
  renderer = gtk_cell_renderer_text_new();
  column = gtk_tree_view_column_new();
  gtk_tree_view_column_set_title(column , "volume name");
  gtk_tree_view_column_pack_start(column , renderer , FALSE);
  gtk_tree_view_column_set_attributes(column , 
									  renderer ,
									  "text" , 
									  1,
									  NULL);
  gtk_tree_view_append_column(GTK_TREE_VIEW(m_hierarchyview) , 
							  column);

  gtk_tree_view_set_headers_visible(m_hierarchyview,
									FALSE);
  return true;
}


/**
 * This method create Notebook widget inserted two tree view,
 * and lets hbox to include Notebook widget.
 * @param hbox This packing window will involve Notebook widget created.
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-5-19
 */
bool GlobalParameter::createNotebook(GtkWidget* hbox)
{
  GtkWidget* notebook = gtk_notebook_new();
  gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), FALSE);
  gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP);

  // Enable scrolling treeviwe 
  GtkWidget* scrolledwindow = gtk_scrolled_window_new(NULL,NULL);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow),
								 GTK_POLICY_AUTOMATIC,
								 GTK_POLICY_AUTOMATIC);
  gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwindow),
									  GTK_SHADOW_IN);
  gtk_widget_set_size_request(GTK_WIDGET(m_hierarchyview),
							  NOTEBOOK_WIDTH,
							  NOTEBOOK_HEIGHT);
  gtk_widget_show(GTK_WIDGET(m_hierarchyview));

  gtk_container_add(GTK_CONTAINER(scrolledwindow),
					GTK_WIDGET(m_hierarchyview));
  
  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
						   scrolledwindow,
						   gtk_label_new(HIERARCHY_VIEW_TAB_LABEL));
  gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
						   GTK_WIDGET(m_attributeview),
						   gtk_label_new(ATTRIBUTE_VIEW_TAB_LABEL));

  // Insert horizon packing
  gtk_box_pack_start(GTK_BOX(hbox), notebook, FALSE, FALSE, 0);

  gtk_widget_show(notebook);
  return true;
}

/**
 * You must call this method before calling createRenderingManager.
 * Because, createRenderingManager method use m_parent_drawarea created 
 * by this method.
 *
 * @param hbox This packing window will involve Notebook widget created.
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-5-20
 */
bool GlobalParameter::createParentDrawArea(GtkWidget* hbox)
{
  m_parent_drawarea = gtk_drawing_area_new();
  gtk_widget_set_size_request(m_parent_drawarea,
							  DRAW_AREA_WIDTH,
							  DRAW_AREA_HEIGHT);
  gtk_widget_set_events(m_parent_drawarea, 
						gtk_widget_get_events(m_parent_drawarea)
						| GDK_EXPOSURE_MASK
						| GDK_BUTTON_PRESS_MASK
						| GDK_POINTER_MOTION_MASK
						);
  gtk_widget_show_all(m_main_window);
  gtk_box_pack_start(GTK_BOX(hbox), m_parent_drawarea, TRUE, TRUE, 0);
  
  gtk_widget_show(m_parent_drawarea);

  //Equip draw area with callback for resize events.
  g_signal_connect(G_OBJECT(m_parent_drawarea),
				   "size-allocate",
                   G_CALLBACK(cb_size_allocate), NULL);

  // Equip draw area with callback for mouse button pressed events.
  g_signal_connect(G_OBJECT(m_parent_drawarea),
				   "button_press_event",
				   G_CALLBACK(cb_button_press_event),
				   NULL);

  // Equip draw area with callback for mouse moved events.
  g_signal_connect(G_OBJECT(m_parent_drawarea),
				   "motion_notify_event",
				   G_CALLBACK(cb_motion_notify_event),
				   NULL);

  // Equip draw area with callback for mouse event
  g_signal_connect(G_OBJECT(m_parent_drawarea),
				   "scroll_event",
				   G_CALLBACK(cb_scroll_event),
				   NULL);

}

//=============================================================================
//	GlobalParameter's static memthod
//=============================================================================
/**
 * @return GlobalParameter::instance
 * @author suzuki ryoutoku
 * @date 2007-12-17
 * @version 1.0
 */
GlobalParameter* GlobalParameter::getInstance()
{
  return &(GlobalParameter::instance);
}

//=============================================================================
//	GlobalParameter's static member
//=============================================================================
/**
 * unique instance
 * @author suzuki ryoutoku
 * @date 2007-12-17
 * @version 1.0
 */
GlobalParameter GlobalParameter::instance;


//=============================================================================
//	Global parameter
//=============================================================================
/**
 * For debug, test 3d draw command.
 * @author r-suzuki
 * @date 2007-10-8
 * @version 1.0
 */
TestCommand* g_test_command;


//=============================================================================
//	Defin function
//=============================================================================
/**
 * When application is idle state, This function is called.
 * \note
 * I want to catch xwindow's event(exposure) in gtk. 
 * But I cannot catch it, so I write this funtion in order to catch xwindow
 * event in idle state.
 * 
 * Work is eval require to redraw 3d draw window(xwindow).
 *
 * @param arg no matter
 *
 * @return always true
 *
 * @author suzuki ryoutoku
 * @date 2007-11-20
 * @version 1.0
 */
gboolean idlefunc(void* arg)
{
  GlobalParameter* gp = GlobalParameter::getInstance();
  gdk_threads_enter();
  {
	XEvent ev;
	if( XCheckWindowEvent( gp->getM_rm()->getM_display(),
						   gp->getM_rm()->getM_window_id(),
						   ExposureMask,
						   &ev) ){
#ifdef DEBUG
	  cout << "exposure" << endl;
#endif
	  gp->getM_rm()->draw();
	}
  }
  gdk_threads_leave();

  return true;
}


/**
 * Application's entry point
 * @author name
 * @date 2007-7-21
 * @version 1.0
 */
int main(int argc, char* argv[])
{
  GlobalParameter* gp = GlobalParameter::getInstance();
  gp->initializeaLogManager();

  //Initialize gthread
  g_thread_init(NULL);
  gdk_threads_init();

  //Initialize gtk & parse application's argument.
  gtk_init(&argc,&argv);
  gtk_set_locale();

  //Creating root window.
  gp->setM_main_window(CreateMainWindow());

  //Create vertical packing
  GtkWidget* vbox = gtk_vbox_new(FALSE, 2);
  gtk_container_add(GTK_CONTAINER(gp->getM_main_window()), vbox);

  //Insert menu to vertical packing window
  gtk_box_pack_start(GTK_BOX(vbox), CreateMenuBar(), FALSE, FALSE, 0);

  //Create horizon packing widget
  GtkWidget* hbox = gtk_hbox_new(FALSE, 2);
  // Insert horizon packing widget to vertical packing widget
  gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);

  //Create Hierarchy view window
  gp->createHierarchyViewWindow();

  //Create Attribute view window 
  gp->createAttributeViewWindow();

  //Create Notebook widget and Insert Notebook widget to horizon packing widget
  gp->createNotebook(hbox);
  
  //Create draw area
  gp->createParentDrawArea(hbox);

  // Create rendereringmanager class.
  gp->createRenderingManager(LogManager::getInstance());

  // Create background
  gp->createBackground();

  // create default data
  gp->createDefaultData();

  // initialize drawing string
  gp->createDrawingString();

#if 0 //test command
  TestCommand* test = new TestCommand();
  test->setOriginalFunction(TestFunction);
  gp->getM_rm()->getM_screen(0)->registGraphicalCommand(test);
#endif
  gp->getM_rm()->draw();
  gtk_idle_add(idlefunc,NULL);

  // thread safety 
  gdk_threads_enter();
  {
	gtk_main();
  }
  gdk_threads_leave();

  return 0;
}

/**
 * Callback for file chooser dialog's ok button
 * \note
 * @param w this is button widget
 * @param fs dialog
 * @author suzuki ryoutoku
 * @date 2007-8-3
 * @version 1.0
 */
void file_ok_sel(GtkWidget *w, GtkFileSelection *fs)
{
  GlobalParameter* gp = GlobalParameter::getInstance();
  GtkTreeStore* store 
	= GTK_TREE_STORE(gtk_tree_view_get_model(gp->getM_hierarchyview()));
  GtkTreeStore* store_attributeview 
	  = GTK_TREE_STORE(gtk_tree_view_get_model(gp->getM_attributeview()));
  
  char* tmp= (char*)gtk_file_selection_get_filename (GTK_FILE_SELECTION (fs) );
  if( gp->getM_model() != NULL ){
	gp->releaseModelData();
	gtk_tree_store_clear(store);
	gtk_tree_store_clear(store_attributeview);

	// clear mouse coordinate
	gp->resetMouseCoordinate();
  }
  // reinitialize line menu item
  gtk_check_menu_item_set_active((GtkCheckMenuItem*)gp->getM_line_menu(), 
								 FALSE);

  // Copy string to represent data directory 
  strcpy(gp->getM_data_directory(),tmp);
  for( int i = strlen(gp->getM_data_directory()) -1; i > 0 ;i -- ){
	if( gp->getM_data_directory()[i] == '/' ){
	  break;
	}else{
	  gp->getM_data_directory()[i] = '\0';
	}
  }

  // read file
  string filename(tmp);
  if( string::npos != filename.rfind("pcm") ||
	  string::npos != filename.rfind("PCM") ){
	ReadPcm rp(LogManager::getInstance());
	gp->setM_model( rp.readPCMFile(filename) );

  }else if( string::npos != filename.rfind("obj") ||
			string::npos != filename.rfind("OBJ") ){
	ReadObj ro(LogManager::getInstance());
	gp->setM_model( ro.readOBJFile(filename) );

  }else if( string::npos != filename.rfind("3ds") ||
			string::npos != filename.rfind("3DS") ){
	Read3ds r3(LogManager::getInstance());
	gp->setM_model( r3.read3DS(filename) );
	gp->readTextureFile(&r3);
	gp->getM_model()->setTextureID(ImageDataManager::getInstance());
  }
  // initialize model data
  if( gp->getM_model() != NULL ){
	gp->getM_model()->getM_coordinate()->setM_pivot(Vector<double>(0.0,
																   0.0,
																   0.0,
																   0.0));
	gp->getM_rm()->getM_screen(0)->registGraphicalCommand(gp->getM_model());
	gp->getM_rm()->getM_screen(0)->getM_camera()->moveToFitModel(gp->getM_model());
	double depth;
	double height;
	double width;
	gp->getM_model()->computeSize(&width,&height,&depth);
	if( width > height ){
	  if( width > depth ){
		gp->setM_div(width/200.0);
	  }else{
		gp->setM_div(depth/200.0);
	  }
	}else{
	  if( height > depth ){
		gp->setM_div(height/200.0);
	  }else{
		gp->setM_div(depth/200.0);
	  }
	}
	gp->setM_selection(new DrawPolygons(true, 
									  gp->getM_model()->getM_vertex(),
									  gp->getM_model()->getM_normal(),
									  gp->getM_model()));
	gp->getM_rm()->getM_screen(0)->registGraphicalCommand(gp->getM_selection());
  }

  // dispatch file chooser dialog
  gtk_widget_destroy((GtkWidget*)fs);

  // if error occur!
  if( gp->getM_model() == NULL ){
	char warning_message[256];
	sprintf(warning_message,
			"error !! can not read file...");
	GtkWidget* messagebox = 
	  gtk_message_dialog_new_with_markup(NULL,
										 GTK_DIALOG_MODAL,
										 GTK_MESSAGE_WARNING,
										 GTK_BUTTONS_CLOSE,
										 warning_message);
	gtk_dialog_run(GTK_DIALOG(messagebox));
	gtk_widget_destroy(messagebox);
	return;
  }

  // setting tree view
  for(int i = 0; i < gp->getM_model()->getM_volume_sum(); i++ ){
	GtkTreeIter ite;
	gtk_tree_store_append(store, &ite, NULL);//no parent
	gtk_tree_store_set(store, 
					   &ite,
					   0,
					   GL_TRUE,
					   1,
					   gp->getM_model()->getM_volume()[i].getM_name(),
					   -1);

	GtkTreeIter childite;
	
	for(int j=0; j < gp->getM_model()->getM_volume()[i].getM_group_sum(); j++){
	  char tmp[256];
	  sprintf(tmp, 
			  "group%d", 
			  gp->getM_model()->getM_volume()[i].getM_group()[j].getM_index());
	  gtk_tree_store_append(store, &childite, &ite);
	  gtk_tree_store_set(store, 
						 &childite,
						 0,GL_TRUE,
						 1,tmp,
						 -1);
	}

  }

  // setting attribute view
  InitializeAttributeView(gp->getM_attributeview(), store_attributeview, false);

  // update font infomation for xwindow
  gp->getM_rm()->updateFont();
  char message[256];
  int face_sum = gp->getM_model()->getFaceSum();
  int node_sum = gp->getM_model()->getM_vertex_sum();
  
  sprintf(message,
		  "face sum = %d node sum = %d",
		  face_sum,
		  node_sum);
  gp->getM_shapeinfomation()->setM_message(message);

  // publish draw command
  gtk_widget_queue_draw(GTK_WIDGET(gp->getM_main_window()));
}

/**
 * Callback of event to press pressing cancel button in file chooser dialog.
 * @author suzuki ryoutoku
 * @date 2007-8-24
 * @version 1.0
 */
void file_cancel_sel(GtkWidget *w, GtkFileSelection *fs)
{
  gtk_widget_destroy((GtkWidget*)fs);
}

/**
 * Callback of event press menu items
 * \note
 * This function is multiple items.
 * Multiple menu items are open menu, about menu, lighting menu.
 * @param string when this function registed, sepcify param.
 * @author suzuki ryoutoku
 * @date 2007-8-3
 * @version 1.0
 */
void cb_menuitem_response(gchar* string)
{
  GlobalParameter* gp = GlobalParameter::getInstance();
  if( NULL != strstr((char*)string,OPEN_PCMFILE_MENU) ){
	// get user's home directory
	chdir(gp->getM_data_directory());

	GtkWidget* file_select 
	  = gtk_file_selection_new(string);
	gtk_file_selection_complete(GTK_FILE_SELECTION(file_select),
								"*.pcm");

	
	/* equip file_ok_sel with ok_button */
	gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(file_select)->ok_button),
					   "clicked", 
					   (GtkSignalFunc) file_ok_sel, 
					   file_select );
	// push cancel button
	gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION
								  (file_select)->cancel_button),
					   "clicked",
					   (GtkSignalFunc)file_cancel_sel,
					   file_select );

	gtk_window_set_modal(GTK_WINDOW(file_select),TRUE);
	gtk_widget_show(file_select);
	
  }else if( NULL != strstr((char*)string,OPNE_OBJFILE_MENU) ){
	// get user's home directory
	chdir(gp->getM_data_directory());

	GtkWidget* file_select 
	  = gtk_file_selection_new(string);
	gtk_file_selection_complete(GTK_FILE_SELECTION(file_select),
								"*.obj");

	
	/* equip file_ok_sel with ok_button */
	gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(file_select)->ok_button),
					   "clicked", 
					   (GtkSignalFunc) file_ok_sel, 
					   file_select );
	// push cancel button
	gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION
								  (file_select)->cancel_button),
					   "clicked",
					   (GtkSignalFunc)file_cancel_sel,
					   file_select );

	gtk_window_set_modal(GTK_WINDOW(file_select),TRUE);
	gtk_widget_show(file_select);
	
  }else if( NULL != strstr((char*)string,OPEN_3DSFILE_MENU) ){
	// get user's home directory
	chdir(gp->getM_data_directory());

	GtkWidget* file_select 
	  = gtk_file_selection_new(string);
	gtk_file_selection_complete(GTK_FILE_SELECTION(file_select),
								"*.3ds");

	
	/* equip file_ok_sel with ok_button */
	gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(file_select)->ok_button),
					   "clicked", 
					   (GtkSignalFunc) file_ok_sel, 
					   file_select );
	// push cancel button
	gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION
								  (file_select)->cancel_button),
					   "clicked",
					   (GtkSignalFunc)file_cancel_sel,
					   file_select );

	gtk_window_set_modal(GTK_WINDOW(file_select),TRUE);
	gtk_widget_show(file_select);
	
  }else if( NULL != strstr((char*)string,"about") ){
	// Help => about menu callback
	const gchar *authors[] = {"suzuki",NULL};
	gtk_show_about_dialog(GTK_WINDOW(gp->getM_main_window()),
						  "authors",authors,
						  "version", "0.1.0.0",
						  "license", "Apache License Version 2.0",
						  "website", "http://d.hatena.ne.jp/malibu-bulldog/",
						  "copyright","Copyright (c) 2007-2008 suzuki",
						  NULL);


  }else if( NULL != strstr((char*)string,"Setting Light parameter") ){
	// Display => setting light parameter's callback
	GtkWidget* dialog 
	  = gtk_dialog_new_with_buttons("Setting light parameter",
									GTK_WINDOW(gp->getM_main_window()),
									(GtkDialogFlags)(GTK_DIALOG_MODAL |
									GTK_DIALOG_DESTROY_WITH_PARENT),
									GTK_STOCK_NO,
									GTK_RESPONSE_NO,
									GTK_STOCK_YES,
									GTK_RESPONSE_YES,
									NULL
									);
#ifdef DEBUG
	cout << "setting light " << endl;
#endif
	// lighting ON/OFF
	GtkWidget* hbox = gtk_hbox_new(FALSE, 2);
	GtkWidget* light_on = gtk_radio_button_new_with_label(NULL,
														  "light on");
	gtk_box_pack_start(GTK_BOX(hbox), light_on, GL_TRUE, GL_TRUE, 0);
	GtkWidget* light_off 
	  = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(light_on),
													"light off");
	// initialize 3d model data's lighting parameter
	if( gp->getM_model()->GraphicalCommand::getM_state() & GraphicalCommand::LIGHTING){
	  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(light_on), TRUE);
	}else{
	  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(light_off), TRUE);
	}

	gtk_box_pack_start(GTK_BOX(hbox), light_off, GL_TRUE, GL_TRUE, 0);
	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox) , hbox);
	

	// dialog run
	gtk_widget_show_all(dialog);
	gint response = gtk_dialog_run(GTK_DIALOG(dialog));

	// accept user input
	if( response == GTK_RESPONSE_YES ){
	  // user input of radio button
	  gboolean off_active 
		= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(light_off));

	  if( off_active == TRUE){
		gp->getM_model()->setM_state(gp->getM_model()->getM_state()
									 -GraphicalCommand::LIGHTING);
	  }else{
		gp->getM_model()->setM_state(gp->getM_model()->getM_state()
									 |GraphicalCommand::LIGHTING);
	  }
	}
	// dispatch dialog
	gtk_widget_destroy(dialog);
#ifdef DEBUG
	cout << "dialog end" << endl;
#endif

  }else if( NULL != strstr((char*)string,"Reset coordinate") ){

	// Display => reset coordinate's callback
	Matrix<double> matrix;
	gp->getM_model()->getM_coordinate()->setM_matrix(matrix);
	gp->getM_model()->getM_coordinate()->setM_pivot(Vector<double>(0.0,
																   0.0,
																   0.0,
																   0.0));


  }else if( NULL != strstr((char*)string,"Scaling") ){
	
	// Display => scaling's callback
#if DEBUG
	cout << "scaling" << endl;
#endif
	GtkWidget* dialog 
	  = gtk_dialog_new_with_buttons("Scaling",
									GTK_WINDOW(gp->getM_main_window()),
									(GtkDialogFlags)(GTK_DIALOG_MODAL |
									GTK_DIALOG_DESTROY_WITH_PARENT),
									NULL
									);
	gtk_widget_set_size_request(dialog,
								250,
								120);

	GtkAdjustment* adjustment;
	GtkWidget* scale;
	adjustment  = (GtkAdjustment*)gtk_adjustment_new(1.0, 
													 0.01, 
													 10.0,
													 0.01, 
													 1.0,
													 0.0);
	scale = gtk_hscale_new(adjustment);
	gtk_scale_set_digits(GTK_SCALE(scale), 2);
	gtk_scale_set_draw_value(GTK_SCALE(scale), TRUE);
	gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_BOTTOM);
	g_signal_connect(GTK_SCALE(scale),
					 "value-changed",
					 G_CALLBACK(cb_scaling),
					 (void*)0x00);
	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox) , scale);
	adjustment  = (GtkAdjustment*)gtk_adjustment_new(1.0, 
													 0.01, 
													 10.0,
													 0.01, 
													 1.0,
													 0.0);
	scale = gtk_hscale_new(adjustment);
	gtk_scale_set_digits(GTK_SCALE(scale), 2);
	gtk_scale_set_draw_value(GTK_SCALE(scale), TRUE);
	gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_BOTTOM);
	g_signal_connect(GTK_SCALE(scale),
					 "value-changed",
					 G_CALLBACK(cb_scaling),
					 (void*)0x01);
	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox) , scale);
	adjustment  = (GtkAdjustment*)gtk_adjustment_new(1.0, 
													 0.01, 
													 10.0,
													 0.01, 
													 1.0,
													 0.0);
	scale = gtk_hscale_new(adjustment);
	gtk_scale_set_digits(GTK_SCALE(scale), 2);
	gtk_scale_set_draw_value(GTK_SCALE(scale), TRUE);
	gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_BOTTOM);
	g_signal_connect(GTK_SCALE(scale),
					 "value-changed",
					 G_CALLBACK(cb_scaling),
					 (void*)0x02);
	gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox) , scale);
	
	// dialog run
	gtk_widget_show_all(dialog);
	gint response = gtk_dialog_run(GTK_DIALOG(dialog));
  }else if( NULL != strstr((char*)string, "Create triangle strip") ){
	// create strip
	if( gp->getM_model() == NULL ) return;

	// show dialog to input parameter
	{
	  GtkWidget* dialog 
		= gtk_dialog_new_with_buttons("Setting strip parameter",
									  GTK_WINDOW(gp->getM_main_window()),
									  (GtkDialogFlags)(GTK_DIALOG_MODAL |
													   GTK_DIALOG_DESTROY_WITH_PARENT),
									  GTK_STOCK_NO,
									  GTK_RESPONSE_NO,
									  GTK_STOCK_YES,
									  GTK_RESPONSE_YES,
									  NULL
									  );
	  GtkWidget* hbox = gtk_hbox_new(FALSE, 2);
	  GtkWidget* io = gtk_radio_button_new_with_label(NULL,
													  "IO order");
	  gtk_box_pack_start(GTK_BOX(hbox), io, GL_TRUE, GL_TRUE, 0);
	  GtkWidget* degree 
		= gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(io),
													  "Less than degree");
	  gtk_box_pack_start(GTK_BOX(hbox), degree, GL_TRUE, GL_TRUE, 0);
	  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox) , hbox);
	  gtk_widget_show_all(dialog);
	  gint response = gtk_dialog_run(GTK_DIALOG(dialog));

	  // accept user input
	  
	  gtk_widget_destroy(dialog);
	}



	GtkWidget* dialog 
	  = gtk_dialog_new_with_buttons("Create triangle strip",
									GTK_WINDOW(gp->getM_main_window()),
									(GtkDialogFlags)(GTK_DIALOG_DESTROY_WITH_PARENT),
									NULL
									);
	GtkWidget* progressbar = gtk_progress_bar_new();
	
	gtk_box_pack_start((GtkBox *)((GtkDialog*)dialog)->vbox,
					   progressbar, 
					   FALSE, 
					   FALSE, 
					   0 );
	gtk_widget_show_all(dialog);
	
	gp->setM_progress_dialog(dialog);
	gp->setM_progress((GtkProgressBar*)progressbar);
	gdk_flush();

	gp->setM_strip_counter(0);

	// after get return value
	GError *error = NULL;
	g_thread_create(thread_function, NULL, TRUE, &error);
	gtk_dialog_run(GTK_DIALOG(gp->getM_progress_dialog()));
	
	if( gp->getM_progress_dialog() != NULL ){
	  gtk_widget_destroy(gp->getM_progress_dialog());
	  gp->setM_progress_dialog(NULL);
	  // after, Forcibly stop thread 
	}


	// I reconstruct attribute view.
	GtkTreeStore* store 
	  = GTK_TREE_STORE(gtk_tree_view_get_model(gp->getM_attributeview()));
	gtk_tree_store_clear(store);
	InitializeAttributeView(gp->getM_attributeview(), store, true);
  }


  GdkRectangle rect;
  rect = gp->getM_main_window()->allocation;
  gtk_widget_draw(GTK_WIDGET(gp->getM_main_window()),&rect);
}

/**
 * Callback of event to toggle line's checking
 * \note
 * Work is to toggle 3d model's drawing state.
 * And toggle menu checking.
 * @author r-suzuki
 * @date 2007-10-8
 * @version 1.0
 */
void cb_menu_line_toggled(GtkCheckMenuItem *checkmenuitem)
{
  GlobalParameter* gp = GlobalParameter::getInstance();
  GtkCheckMenuItem* item = (GtkCheckMenuItem*)gp->getM_line_menu();
  if( gp->getM_model() == NULL ){
	return;
  }

  if(gtk_check_menu_item_get_active(item) ){
	gp->getM_model()->setM_state(gp->getM_model()->getM_state()
								 | GraphicalCommand::WIRE_FRAME);
  }else{
	gp->getM_model()->setM_state(gp->getM_model()->getM_state()
								 - GraphicalCommand::WIRE_FRAME);
  }
}

/**
 * Callback of expose event
 * \note
 * Calling RenderingManager's draw and measuring frame rate.
 * 
 * @author suzuki ryoutoku
 * @date 2007-8-17
 * @version 1.0
 */
gint cb_expose(GtkWidget* widget, GdkEventExpose* event, gpointer data)
{
  GlobalParameter* gp = GlobalParameter::getInstance();

  // measure rendering time
  timeval tv_before;
  timeval tv_after;
  char tmp[256];

  gettimeofday(&tv_before, NULL);
  gp->getM_rm()->draw();
  
  gettimeofday(&tv_after, NULL);
  
  sprintf(tmp, 
		  "fps = %f", 
		  1000000.0f/(float)(tv_after.tv_usec - tv_before.tv_usec));
  gp->getM_fps()->setM_message(tmp);
  return 0;
}


/**
 * Callback of main window resize event
 * \note
 * This callback was set RenderingManager's target window.
 * Work is to correspond to resize event.
 * @author suzuki ryoutoku
 * @date 2007-8-17
 * @version 1.0
 */
void cb_size_allocate(GtkWidget * arg1, gpointer arg2, gpointer arg3)
{
  GlobalParameter* gp = GlobalParameter::getInstance();
  if( arg1 == gp->getM_parent_drawarea() ){
#ifdef DEBUG
	cout << "drawarea resize" << endl;
	cout << arg1->allocation.width << " " << arg1->allocation.height << endl;
#endif
	if( gp->getM_rm() != NULL ){
	  gp->getM_rm()->resize(arg1->allocation.width,
							arg1->allocation.height);
	  // change xwindow screen size
	  RECT tmp;
	  tmp.left = 10;
	  tmp.top = 10;
	  tmp.right = arg1->allocation.width - 20;
	  tmp.bottom = arg1->allocation.height - 20;
	  gp->getM_rm()->getM_screen(0)->setM_rect(tmp);
	  if( gp->getM_background() != NULL ){
		gp->getM_background()->setM_rect(0,
										 0,
										 tmp.right - tmp.left,
										 tmp.bottom - tmp.top);
	  }
	}
  }else if( arg1 == gp->getM_main_window() ){
#ifdef DEBUG
	cout << "window resize" << endl;
#endif
	// Now, This program have nothing to do.
  }
}


/**
 * This function's feture is to survey selection in tree views's column.
 * \note
 * This is test.
 * @author suzuki ryoutoku
 * @date 2007-8-15
 * @version 1.0
 */
void select_list(GtkTreeView *treeview)
{
  GtkTreeSelection *selection;

  selection = gtk_tree_view_get_selection (treeview);
  if (NULL == selection) return;
#ifdef DEBUG
  cout << "select" << endl;
#endif
}


/**
 * Callback of click event
 * \note
 * Apply this function draw window.
 * @author suzuki ryoutoku
 * @date 2007-8-17
 * @version 1.0
 */
gboolean cb_button_press_event(GtkWidget* widget, 
							   GdkEventButton* event, 
							   gpointer data)
{
#ifdef DEBUG
  cout << "press" << endl;
#endif
  GlobalParameter* gp = GlobalParameter::getInstance();

  if( gp->getM_keystate() == GDK_Control_L ||
	  GDK_Control_R == gp->getM_keystate() ){
	POINT point;
	if( gp->getM_model() == NULL )return false;
	point.x = (long unsigned int)event->x;
	point.y = (long unsigned int)event->y;
	int index = gp->getM_rm()->selectionPolygon(point,
												gp->getM_model(),
												gp->getM_rm()->getM_screen(0));
	
	if( index >= 0 ){
	  Polygon poly = gp->getM_model()->queryPolygon(index);
	  poly.displayInConsole();
	  if( false == gp->getM_selection()->addPolygon(poly) ){
		gp->getM_selection()->removePolygon(index);
	  }
	  gtk_widget_queue_draw(GTK_WIDGET(gp->getM_main_window()));
	}
  }
  return FALSE;
}

/**
 * Callback of event to be focused main window.
 * \note
 * Publish draw command.
 * This function was set root window.
 * @author suzuki ryoutoku
 * @date 2007-8-18
 * @version 1.0
 */
gboolean cb_focus_in_event(GtkWidget *,
						   GdkEvent *,
						   gpointer)
{
#ifdef DEBUG
  cout << "focuse in " << endl;
#endif
  GlobalParameter* gp = GlobalParameter::getInstance();
  gtk_widget_queue_draw(GTK_WIDGET(gp->getM_main_window()));
}


/**
 * Callback of event moiving mouse 
 * \note
 * Work is correspond to motion notify event.
 * If user press mouse button3, model rotate by trackball algorism.
 * If user press mouse button1, model move along x-axis and y-axis.
 * If user press mouse button2, model move along z-axis.
 * @author r-suzuki
 * @date 2007-9-29
 * @version 1.0
 */
gboolean cb_motion_notify_event(GtkWidget         *widget,
                                GdkEventMotion      *event)
{
  GlobalParameter* gp = GlobalParameter::getInstance();
#if 0
  cout << "motion" << endl;
#endif
  if( gp->getM_model() == NULL ) return false;
  double W = (double)(gp->getM_rm()->getM_window_width());
  double H = (double)(gp->getM_rm()->getM_window_height());
  double rate_x = 2.0f;
  double rate_y = 2.0f;
  static Quaternion<double> quaternion;
  if( event->state & GDK_BUTTON3_MASK){
	// Rotate by trackball
	double p1x = (     2.0f * ((double)gp->getM_before_x()) - W  ) / W;
	double p1y = ( H - 2.0f * ((double)gp->getM_before_y())      ) / H;
	double p2x = (     2.0f * ((double)event->x)             - W ) / W;
	double p2y = ( H - 2.0f * ((double)event->y)                 ) / H;
	quaternion *= Quaternion<double>::Trackball(p1x, p1y, p2x, p2y);
	Matrix<double> mat(quaternion);
	gp->getM_model()->getM_coordinate()->setM_matrix(mat);

	gp->setM_before_x(event->x);
	gp->setM_before_y(event->y);

	gtk_widget_queue_draw(GTK_WIDGET(gp->getM_main_window()));
  }else if(event->state & GDK_BUTTON1_MASK){
	gdouble x = event->x - gp->getM_before_x();
	gdouble y = event->y - gp->getM_before_y();
	double div = gp->getM_div();

	if( x > 0 ){
	  gp->getM_model()->getM_coordinate()->getM_pivot()->x+=div;
	}else if( x < 0 ){
	  gp->getM_model()->getM_coordinate()->getM_pivot()->x-=div;
	}
	if( y > 0 ){
	  gp->getM_model()->getM_coordinate()->getM_pivot()->y-=div;
	}else if( y < 0){
	  gp->getM_model()->getM_coordinate()->getM_pivot()->y+=div;
	}


	gp->setM_before_x(event->x);
	gp->setM_before_y(event->y);
	gtk_widget_queue_draw(GTK_WIDGET(gp->getM_main_window()));
  }else if(event->state & GDK_BUTTON2_MASK){
	gdouble z = event->y - gp->getM_before_z();
	gp->setM_before_z(event->y);
	double div = gp->getM_div();

	if( z > 0 ){
	  gp->getM_model()->getM_coordinate()->getM_pivot()->z-=div;
	}else if( z < 0){
	  gp->getM_model()->getM_coordinate()->getM_pivot()->z+=div;
	}
	gtk_widget_queue_draw(GTK_WIDGET(gp->getM_main_window()));
  }else{
	// mouse operation without drag 
	gp->setM_before_x(event->x);
	gp->setM_before_y(event->y);
  }
  
	
}


/**
 * Callback of event to toggle falg in tree view window's colum
 * \note
 * This tree shows hierarchy .
 * @author suzuki ryoutoku
 * @date 2007-10-16
 * @version 1.0
 */
void cb_status_toggled (GtkCellRendererToggle *renderer ,
						gchar *path_string ,
						gpointer user_data)
{
  GlobalParameter* gp = GlobalParameter::getInstance();
  GtkTreeModel *model;
  GtkTreeIter iter;
  GtkTreeIter parent;
  GtkTreePath *path;
  gboolean status;
  char* name;
  char *parent_name;
  gboolean ischild;
  
  model = gtk_tree_view_get_model(gp->getM_hierarchyview());
  path = gtk_tree_path_new_from_string(path_string);
  gtk_tree_model_get_iter(model,&iter,path);
  ischild = gtk_tree_model_iter_parent(model,&parent,&iter);

  if( !ischild ){
	// volume
	gtk_tree_model_get(model , &iter, 0 , &status, -1);
	gtk_tree_model_get(model , &iter, 1 , &name, -1);
    gtk_tree_store_set (GTK_TREE_STORE(model) , &iter ,
						0 , !status , -1);
#ifdef DEBUG
	cout << name << endl;
#endif
	
	if( gp->getM_model() == NULL ) return;
	Volume* volume = gp->getM_model()->getM_volume_with_name(name);
	if( volume != NULL ){
	  volume->setM_state( volume->getM_state() ^ 0x01 );
	}
  }else{
	// group
	gtk_tree_model_get(model,&parent, 1,&parent_name,-1);
	gtk_tree_model_get(model , &iter, 0 , &status, -1);
	gtk_tree_model_get(model , &iter, 1 , &name, -1);
#ifdef DEBUG
	cout << "name = " << name << endl;
	cout << "parent name = " << parent_name << endl;
#endif

	Volume* volume = gp->getM_model()->getM_volume_with_name(parent_name);

	if( volume != NULL ){
	  int index;
	  sscanf( name, "group%d", &index);
	  for( int i =0; i < volume->getM_group_sum(); i++){
		if( index == volume->getM_group()[i].getM_index() ){
		  Group* group = &(volume->getM_group()[i]);
		  group->toggleNoDrawing();
		  break;
		}
	  }
	}
	
  }
  gtk_tree_store_set (GTK_TREE_STORE(model) , &iter ,
					  0 , !status , -1);

  gtk_tree_path_free (path);
  gtk_widget_queue_draw(GTK_WIDGET(gp->getM_main_window()));
}

/**
 * Callback of event to click Attribute window.
 * @author suzuki ryoutoku
 * @date 2007-10-18
 * @version 1.0
 */
gboolean cb_tree_item_double_clicked(GtkTreeView *treeview,
									 GtkTreePath *path,
									 GtkTreeViewColumn* column,
									 gpointer data)
{
  GlobalParameter* gp = GlobalParameter::getInstance();
  GtkTreeModel *model;
  GtkTreeIter iter;
  GtkTreeIter parent;
  char *name;
  char *parent_name;
  gboolean ischild;
  model = gtk_tree_view_get_model(treeview);
  gtk_tree_model_get_iter(model,&iter,path);
  gtk_tree_model_get(model,&iter,0,&name,-1);

#ifdef DEBUG
  cout << "child name = " << name << endl;
#endif

  ischild = gtk_tree_model_iter_parent(model,&parent,&iter);

  if( ischild ){

	  gtk_tree_model_get(model,&parent,0,&parent_name,-1);
#ifdef DEBUG
	  cout << "parent name = " << parent_name << endl;
#endif
  }

  if( gp->getM_model() == NULL ) return 0;
  if( !ischild ) return 0;

  
  // change color
  if( NULL != strstr(parent_name,"Color") ){
	Color<float> *color;
	Color<float> red(1.0,0.0,0.0,1.0);
	Color<float> blue(0.4,0.4,0.7,1.0);
	Color<float> green(0.4,0.7,0.4,1.0);
	Color<float> grey(0.7,0.7,0.7,1.0);
	Color<float> yellow(1.0,1.0,0.4,1.0);
	Color<float> white(1.0,1.0,1.0,1.0);
	
	if( NULL != strstr(name,"Red") ){
	  color = &red;
	}else if( NULL != strstr(name,"Blue") ){
	  color = &blue;
	}else if( NULL != strstr(name,"Green") ){
	  color = &green;
	}else if( NULL != strstr(name,"Grey") ){
	  color = &grey;
	}else if( NULL != strstr(name,"Yellow") ){
	  color = &yellow;
	}else if( NULL != strstr(name,"White") ){
	  color = &white;
	}
	gp->getM_model()->coloring(*color);
	
  }else if( NULL != strstr(parent_name,"Draw method") ){
	unsigned int draw_method = 0;
	if( NULL != strstr(name,"Vertex array") ){
	  draw_method = Group::DRAW_DEFAULT;

	}else if(NULL != strstr(name,"Triangle strip") ){
	  draw_method = Group::DRAW_WITH_STRIP;

	}else if( NULL != strstr(name,"Strip with colors") ){
	  draw_method = Group::DRAW_WITH_SEPARATE_COLOR_STRIP;
	}

	for( int j = 0; j < gp->getM_model()->getM_volume_sum(); j++){
	  Volume* volume = &(gp->getM_model()->getM_volume()[j]);
	  for( int i =0; i < volume->getM_group_sum(); i++){
		Group* tmp_group = &(volume->getM_group()[i]);
		tmp_group->setM_draw_method(draw_method);
	  }
	}
  }
  gtk_widget_queue_draw(GTK_WIDGET(gp->getM_main_window()));
}


/**
 * Callback of event to change scroll bar  
 * @author suzuki ryoutoku
 * @date 2007-10-22
 * @version 1.0
 */
void cb_scaling(GtkScale* scale, gpointer data)
{
  GlobalParameter* gp = GlobalParameter::getInstance();
  int axis = (int)data;
  if(gp->getM_model()==NULL)return;
#ifdef DEBUG
  cout << "scaling = " << gtk_range_get_value(GTK_RANGE(scale)) << endl;
#endif

  double factor = gtk_range_get_value(GTK_RANGE(scale));
  Vector<double> svec = *(gp->getM_model()->getM_coordinate()->getM_scale());
  switch( axis ){
  case 0x00:
	svec.x=factor;
	break;
  case 0x01:
	svec.y=factor;
	break;
  case 0x02:
	svec.z=factor;
	break;
  }
  gp->getM_model()->getM_coordinate()->setM_scale(svec);
  

  gtk_widget_queue_draw(GTK_WIDGET(gp->getM_main_window()));
}

/**
 * Callback of event to press key board.
 * \note
 * This function is test.
 * @author suzuki ryoutoku
 * @date 2007-10-23
 * @version 1.0
 */
gboolean cb_key_press_event(GtkWidget *widget,
							GdkEventKey *event)
{
#ifdef DEBUG
  cout << "press key value = " << event->keyval <<" "<< event->string << endl;
#endif
  GlobalParameter* gp = GlobalParameter::getInstance();
  if( GDK_Control_L == event->keyval ){
#ifdef DEBUG
	cout << "control key press" << endl;
#endif
	gp->setM_keystate(GDK_Control_L);
  }else if( GDK_Control_R == event->keyval ){
	gp->setM_keystate(GDK_Control_L);
  }else if( GDK_Shift_L == event->keyval || 
			GDK_Shift_R == event->keyval ){
	// no future ... 
  }
  

  return TRUE;
}

/**
 * Callback of event to release key board.
 * \note
 * This function is test.
 * @author suzuki ryoutoku
 * @date 2007-10-24
 * @version 1.0
 */
gboolean cb_key_release_event(GtkWidget *widget,
							  GdkEventKey *event)
{
#ifdef DEBUG
  cout << "release key value = "<< event->keyval <<" "<< event->string << endl;
#endif
  if( GDK_Control_L == event->keyval ||
	  GDK_Control_R == event->keyval){
#ifdef DEBUG
	cout << "control key release" << endl;
#endif
	GlobalParameter* gp = GlobalParameter::getInstance();
	gp->setM_keystate(0);
  }

  return TRUE;
}

/**
 * Callback of event mouse scroll action.
 * \note
 * If user's mouse have note scroll feature, work is unenable.
 *
 * @param widget
 * @param event
 *
 * @return Only TRUE
 *
 * @author suzuki ryoutoku
 * @date 2007-10-23
 * @version 1.0
 */
gboolean cb_scroll_event(GtkWidget *widget,
						 GdkEventScroll *event)
{
  GlobalParameter* gp = GlobalParameter::getInstance();
#ifdef DEBUG
  cout << "scroll" << endl;
#endif
  double div = gp->getM_div();
  if( gp->getM_model() == NULL ) return false;
  if( event->direction == GDK_SCROLL_UP ){
	gp->getM_model()->getM_coordinate()->getM_pivot()->z-=div;
  }else if( event->direction == GDK_SCROLL_DOWN ){
	gp->getM_model()->getM_coordinate()->getM_pivot()->z+=div;
  }
  gtk_widget_queue_draw(GTK_WIDGET(gp->getM_main_window()));
  return TRUE;
}

/**
 * This function create attribute view window
 * \note
 * @param treeview attribute tree window
 * @param store 
 * @param flag enable triangle strip or not
 *
 * @author suzuki ryoutoku
 * @date 2008-1-7
 * @version 1.0
 */
GtkTreeView* InitializeAttributeView(GtkTreeView* treeview, 
									 GtkTreeStore* store, 
									 bool flag)
{
  GtkTreeIter parent_iter;
  GtkTreeIter iter;
  // color
  gtk_tree_store_append(store, &parent_iter, NULL);
  gtk_tree_store_set(store, &parent_iter,0,"Color",-1);
  gtk_tree_store_append(store, &iter, &parent_iter);
  gtk_tree_store_set(store,&iter,0,"White",-1);
  gtk_tree_store_append(store, &iter, &parent_iter);
  gtk_tree_store_set(store,&iter,0,"Red",-1);
  gtk_tree_store_append(store, &iter, &parent_iter);
  gtk_tree_store_set(store,&iter,0,"Blue",-1);
  gtk_tree_store_append(store, &iter, &parent_iter);
  gtk_tree_store_set(store,&iter,0,"Green",-1);
  gtk_tree_store_append(store, &iter, &parent_iter);
  gtk_tree_store_set(store,&iter,0,"Grey",-1);
  gtk_tree_store_append(store, &iter, &parent_iter);
  gtk_tree_store_set(store,&iter,0,"Yellow",-1);
  // draw method
  gtk_tree_store_append(store, &parent_iter, NULL);
  gtk_tree_store_set(store, &parent_iter,0,"Draw method",-1);
  gtk_tree_store_append(store, &iter, &parent_iter);
  gtk_tree_store_set(store,&iter,0,"Vertex array",-1);
  
  if( flag == true ){
	gtk_tree_store_append(store, &iter, &parent_iter);
	gtk_tree_store_set(store,&iter,0,"Triangle strip",-1);
	gtk_tree_store_append(store, &iter, &parent_iter);
	gtk_tree_store_set(store,&iter,0,"Strip with colors",-1);
  }
  return treeview;
}


/**
 * This method is equiped in a thread.
 * \note
 * Thread builded will start to create triangle strip from model data.
 *
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-1-10
 */
void* thread_function(void* args)
{
  GlobalParameter* gp = GlobalParameter::getInstance();
  
  for( int j = 0; j < gp->getM_model()->getM_volume_sum(); j++){
	Volume* volume = &(gp->getM_model()->getM_volume()[j]);
	for( int i =0; i < volume->getM_group_sum(); i++){
	  StripCreator strip(LogManager::getInstance());
	  Group* tmp_group = &(volume->getM_group()[i]);
	  int** strip_index;
	  int** relative;
	  int* length;
	  int sum = strip.createTriangleStrip(&(strip_index),
										  &(relative),
										  &(length),
										  tmp_group->getM_triangle(),
										  tmp_group->getM_triangle_globalid(),
										  tmp_group->getM_triangle_sum(),
										  gp->getM_model()->getM_vertex_sum());
	  tmp_group->setM_strip_index(strip_index);
	  tmp_group->setM_relative_index(relative);
	  tmp_group->setM_strip_length(length);
	  tmp_group->setM_strip_sum(sum);
	  tmp_group->setM_draw_method(Group::DRAW_WITH_STRIP);
	  Color<float>* colors = new Color<float>[sum];
	  for( int j = 0; j < sum; j++ ){
		int tmp = rand();
		colors[j] = Color<float>(tmp);
	  }
	  tmp_group->setM_strip_color(colors);
	  tmp_group->toggleStripAttribute();
	  gp->setM_strip_counter(gp->getM_strip_counter()+1);

	  gdk_threads_enter();
	  {
		double per 
		  = (double)(gp->getM_strip_counter())
		  /(double)(gp->getM_model()->getNumberOfGroups());
		GtkProgressBar* pb = (GtkProgressBar*)(gp->getM_progress());
		if( per < 1.0 ){
		  gdouble new_val = per;
		  cout << "now value=" << gtk_progress_bar_get_fraction(pb) << endl;
		  
		  
		  gtk_progress_bar_set_fraction(pb,new_val);
		  gdk_flush();
		}else{
		  gtk_widget_destroy(gp->getM_progress_dialog());
		  gp->setM_progress_dialog(NULL);
		}
	  }
	  gdk_threads_leave();
	}
	
  }
  gp->getM_model()->setM_strip_flag(true);

  return NULL;
}

/**
 * This function is to create bitmapdata from jpg file
 * 
 * @param info This is set bitmap infomation.
 * @param bitpattern This is allocated memory and copied pixel pattern.
 * @param name This is filename.
 *
 * @author suzuki ryoutoku 
 * @date 2008-2-3
 * @version 1.0
 */
bool CreateBitmapFromJpgfile(BITMAPINFO* info,
							 unsigned int** bitpattern, 
							 const char* name)
{
  GError* error = NULL;
  GdkPixbuf* pixbuf = NULL;
  pixbuf = gdk_pixbuf_new_from_file(name,
									&error);
  if( pixbuf == NULL ){
	cout << "error->code:" << error->code << endl;
	cout << "error->message:" << error->message << endl;
	return false;
  }

#ifdef DEBUG
  // display infomations of jpg 
  cout << "width = " << gdk_pixbuf_get_width(pixbuf) << endl;
  cout << "height = " << gdk_pixbuf_get_height(pixbuf) << endl;
  cout << "bits per sample = " << gdk_pixbuf_get_bits_per_sample(pixbuf)<<endl;
#endif

  guchar* pixel = gdk_pixbuf_get_pixels(pixbuf);
  int width = gdk_pixbuf_get_width(pixbuf);
  int height = gdk_pixbuf_get_height(pixbuf);
  int linewidth= gdk_pixbuf_get_rowstride(pixbuf);
  *bitpattern = new unsigned int[width*height];

  for( int i = 0; i < height; i ++ ){
	for( int j = 0; j < width; j ++ ){
	  unsigned int R = (int)(pixel[i*linewidth+j*3+0]);
	  unsigned int G = (int)(pixel[i*linewidth+j*3+1]);
	  unsigned int B = (int)(pixel[i*linewidth+j*3+2]);
	  unsigned int data = ((B << 16 )&0xFF0000)+((G << 8)&0xFF00)+R;
	  (*bitpattern)[(height-1-i)*width + j ] = data;
	}
  }
  info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  info->bmiHeader.biWidth = width;
  info->bmiHeader.biHeight = height;
  info->bmiHeader.biPlanes = 1;
  info->bmiHeader.biBitCount = 32;
  info->bmiHeader.biCompression = 0;
  info->bmiHeader.biSizeImage = 0;
  info->bmiHeader.biXPelsPerMeter = 0;
  info->bmiHeader.biYPelsPerMeter = 0;
  info->bmiHeader.biClrUsed= 0;
  info->bmiHeader.biClrImportant = 0;

  
  g_object_unref(pixbuf);
  return true;
}


void TestFunction(library::graphics::Screen* screen)
{
  GLint vp[4];

  // set polygon mode
  ::glEnable( GL_POLYGON_OFFSET_FILL );
  ::glPolygonOffset( 0.5, 0.5 );
  ::glPolygonMode( GL_FRONT, GL_FILL );

  // setting my coordinate
  ::glMatrixMode(GL_MODELVIEW);
  ::glPushMatrix();
  ::glLoadIdentity();
  //this->getM_coordinate()->settingOpenGL();
    
  
  // enable transparent
  ::glAlphaFunc(GL_GREATER, 0.5);// when alpha less than 0xFF>>1
  ::glEnable(GL_ALPHA_TEST); 

  Color<float> color2(0.0, 0.0, 0.0, 0.0);
  ::glMaterialfv(GL_FRONT,GL_AMBIENT,  color2.color);
  Color<float> color3(0.0, 0.0, 0.0, 0.0);
  ::glMaterialfv(GL_FRONT,GL_SPECULAR, color3.color);
  // enable variable material color within glBegin~glEnd
  ::glEnable( GL_COLOR_MATERIAL );
  // variable color is diffuse
  ::glColorMaterial(GL_FRONT, GL_DIFFUSE);
  // enable lighting
  ::glEnable( GL_LIGHTING );
  

  // if you want semi transparency, set a to 0.6, 0.5, 0.4...
  ::glMatrixMode(GL_MODELVIEW);
  ::glLoadIdentity();

  ::glMatrixMode(GL_MODELVIEW);

  ::glColor3d( 1.0, 1.0, 0.4);
  ::glBegin(GL_TRIANGLE_STRIP);
  {
	::glNormal3d(0.0,0.0,1.0);
	::glVertex3d(0.0,
				 0.0,
				 1.0);
	
	::glVertex3d(1.0,
				 0.0,
				 1.0);

	::glVertex3d(0.0,
				 1.0,
				 1.0);

	::glVertex3d(0.0,
				 0.0,
				 1.0);

	::glNormal3d(0.0,0.0,1.0);
	::glVertex3d(-1.0,
				 1.0,
				 1.0);
  }
  ::glEnd();

  
  // disable testing alpha
  ::glDisable(GL_ALPHA_TEST); 
  // cancel depth buffer
  ::glClear( GL_DEPTH_BUFFER_BIT );

  ::glMatrixMode(GL_MODELVIEW);
  ::glPopMatrix();
}


/**
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-4-23
 */
GtkWidget* CreateMainWindow(void)
{
  GtkWidget* mainwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_widget_add_events(mainwindow, GDK_FOCUS_CHANGE_MASK );
  // Setting style root window.
  gtk_window_set_title(GTK_WINDOW(mainwindow), APPLICATION_NAME);
  // Setting root window size
  gtk_widget_set_size_request(mainwindow, 
							  MAIN_WINDOW_WIDTH,
							  MAIN_WINDOW_HEIGHT);

  g_signal_connect(G_OBJECT(mainwindow), 
				   "destroy",
				   G_CALLBACK(gtk_main_quit),
				   NULL);
  g_signal_connect(GTK_WIDGET(mainwindow), 
				   "size-allocate",
                   G_CALLBACK(cb_size_allocate), NULL);
  
  // Equip root window with callback for draw 3d
  g_signal_connect(G_OBJECT(mainwindow),
				   "expose_event",
				   G_CALLBACK(cb_expose),
				   NULL);

  // Equip root window with callback for focus in
  g_signal_connect(G_OBJECT(mainwindow),
				   "focus_in_event",
				   G_CALLBACK(cb_focus_in_event),
				   NULL);

  // Equip root window with callback keyboard event
  g_signal_connect(G_OBJECT(mainwindow),
				   "key_press_event",
				   G_CALLBACK(cb_key_press_event),
				   NULL);
  // Equip root window with callback keyboard event
  g_signal_connect(G_OBJECT(mainwindow),
				   "key_release_event",
				   G_CALLBACK(cb_key_release_event),
				   NULL);

  return mainwindow;
}

/**
 * This function is creating main menu bar of main window and sub menu equiped.
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-4-23
 */
GtkWidget* CreateMenuBar(void)
{
  GtkWidget* menu = gtk_menu_bar_new();
  // 'File' main menu bar item, 'File' have sub menu bar.
  GtkWidget* item1 = gtk_menu_item_new_with_label("File");

  // 'Display' main menu bar item, 'Display' have sub menu bar.
  GtkWidget* item2 = gtk_menu_item_new_with_label("Display");

  // 'Edit' is itme of main menu bar, 'Edit' have sub menu bar.
  GtkWidget* item3 = gtk_menu_item_new_with_label("Create");

  // 'Help' main menu bar item.
  GtkWidget* item4 = gtk_menu_item_new_with_label("Help");

  
  // Add 3 items to menu bar
  gtk_menu_bar_append(GTK_MENU_BAR(menu), item1);
  gtk_menu_bar_append(GTK_MENU_BAR(menu), item2);
  gtk_menu_bar_append(GTK_MENU_BAR(menu), item3);
  gtk_menu_bar_append(GTK_MENU_BAR(menu), item4);
  
  // Creating 'File' submenu contents
  GtkWidget* submenu = gtk_menu_new();

  GtkWidget* submenu_item;
  {
	submenu_item = gtk_menu_item_new_with_label(OPEN_PCMFILE_MENU);
	gtk_menu_append(GTK_MENU(submenu), submenu_item);
	
	// Setting callback function
	gtk_signal_connect_object (GTK_OBJECT (submenu_item), 
							   "activate",
							   GTK_SIGNAL_FUNC(cb_menuitem_response), 
							   (void*)OPEN_PCMFILE_MENU);
  }

  	
  // To associate submenu with main menu's item
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(item1),submenu);
  
  {
	submenu_item = gtk_menu_item_new_with_label(OPNE_OBJFILE_MENU);
	gtk_menu_append(GTK_MENU(submenu), submenu_item);
	
	// Setting callback function
	gtk_signal_connect_object (GTK_OBJECT (submenu_item), 
							   "activate",
							   GTK_SIGNAL_FUNC(cb_menuitem_response), 
							   (void*)OPNE_OBJFILE_MENU);
  }
  {
	submenu_item = gtk_menu_item_new_with_label(OPEN_3DSFILE_MENU);
	gtk_menu_append(GTK_MENU(submenu), submenu_item);
	// Setting callback function
	gtk_signal_connect_object (GTK_OBJECT (submenu_item), 
							   "activate",
							   GTK_SIGNAL_FUNC(cb_menuitem_response), 
							   (void*)OPEN_3DSFILE_MENU);
  }
  // To associate submenu with main menu's item
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(item1),submenu);



  // Creating 'Display' submenu contents
  submenu = gtk_menu_new();
  submenu_item
	= gtk_check_menu_item_new_with_label("Display polygon line");

  GlobalParameter::getInstance()->setM_line_menu(submenu_item);
  // Above code is call the method to create check item
  gtk_menu_append(GTK_MENU(submenu), submenu_item);

  // Setting callback for cheking on or off
  gtk_signal_connect_object (GTK_OBJECT (submenu_item), 
							 "toggled",
							 GTK_SIGNAL_FUNC(cb_menu_line_toggled), 
							 NULL);
  gtk_check_menu_item_set_active((GtkCheckMenuItem*)submenu_item, FALSE);
  
  // Setting Light parameter's menu
  submenu_item = gtk_menu_item_new_with_label("Setting Light parameter");
  gtk_menu_append(GTK_MENU(submenu), submenu_item);
  // To equip callback with selection item.
  gtk_signal_connect_object (GTK_OBJECT (submenu_item), 
							 "activate",
							 GTK_SIGNAL_FUNC(cb_menuitem_response), 
							 (void*)"Setting Light parameter");

  // Setting reset coordinate's menu
  submenu_item = gtk_menu_item_new_with_label("Reset coordinate");
  gtk_menu_append(GTK_MENU(submenu), submenu_item);
  gtk_signal_connect_object (GTK_OBJECT (submenu_item), 
							 "activate",
							 GTK_SIGNAL_FUNC(cb_menuitem_response), 
							 (void*)"Reset coordinate");

  // Setting scaling 's menu
  submenu_item = gtk_menu_item_new_with_label("Scaling");
  gtk_menu_append(GTK_MENU(submenu), submenu_item);
  gtk_signal_connect_object(GTK_OBJECT (submenu_item), 
							"activate",
							GTK_SIGNAL_FUNC(cb_menuitem_response), 
							(void*)"Scaling");
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(item2),submenu);
  
  // Creating 'Edit' menu contents
  submenu = gtk_menu_new();

  submenu_item = gtk_menu_item_new_with_label("Create triangle strip");
  gtk_menu_append(GTK_MENU(submenu), submenu_item);

  // To equip callback , event is selection submenu item.
  gtk_signal_connect_object (GTK_OBJECT (submenu_item), 
							 "activate",
							 GTK_SIGNAL_FUNC(cb_menuitem_response), 
							 (void*)"Create triangle strip");
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(item3),submenu);


  // Creating 'Help' menu contents
  submenu = gtk_menu_new();

  submenu_item = gtk_menu_item_new_with_label("About StripExperiment");
  gtk_menu_append(GTK_MENU(submenu), submenu_item);

  // To equip callback , event is selection submenu item.
  gtk_signal_connect_object (GTK_OBJECT (submenu_item), 
							 "activate",
							 GTK_SIGNAL_FUNC(cb_menuitem_response), 
							 (void*)"about");
  gtk_menu_item_set_submenu(GTK_MENU_ITEM(item4),submenu);


  return menu;
}
